/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = ora_ttc8_tti_lobd.c                                */
/*  NOTE      =                                                    */
/*  DATE      = 2015/03/16 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <frct_comm.h>

#include "frcomm.h"
#include "frstr.h"
#include "frmem.h"
#include "frlog.h"

#include "../../ora_core.h"
#include "../../comm/ora_comm.h"
#include "../../comm/ora_util.h"
#include "../ora_mar_engine.h"
#include "ora_ttc8_tti_lobd.h"


/*******************************************************************************
*  FUNC     :  对应于 ojdbc7_12.1.0.1 oracle.jdbc.driver.T4C8TTILobd.java unmarshalClobUB2_For9iDB()
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_ttc8_tti_lobd_unmarshalClobUB2_For9iDB(Conntrack *p_st_conn
                                            , L7session_ora *p_st_sess
                                            , L7_ora_packet *p_st_ora_packet)
{
    ORA_PRINT_INFO("ora_ttc8_tti_lobd_unmarshalClobUB2_For9iDB...\n");
    short s_i = 0;
    int j_loop = 0;
    int i_k = 0;
    int m = 0;
    while (m != 4)
    {
        switch (m)
        {
            case 0:
                if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_i) != FR_SUCC) // i
                    goto error;
                if (s_i == 254)
                    m = 2;
                else
                    m = 1;
                break;
            case 1:
                for (j_loop = 0; j_loop < s_i;)
                {
                    if (p_st_sess->i_use_special_field == FR_YES && s_i - j_loop == 1)
                    {
                        if (ora_mar_skip(p_st_ora_packet, 1) != FR_SUCC)
                            goto error;
                        i_k = 1;
                    }
                    else
                    {
                        if (ora_mar_unmarshalUCS2(p_st_sess, p_st_ora_packet, &i_k) != FR_SUCC) // k
                            goto error;
                    }
                    j_loop += i_k;
                }
                m = 4;
                break;
            case 2:
                if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_i) != FR_SUCC) // i
                    goto error;
                if (s_i > 0)
                    m = 3;
                else
                    m = 4;
                break;
            case 3:
                for (j_loop = 0; j_loop < s_i;)
                {
                    if (p_st_sess->i_use_special_field == FR_YES && s_i - j_loop == 1)
                    {
                        if (ora_mar_skip(p_st_ora_packet, 1) != FR_SUCC)
                            goto error;
                        i_k = 1;
                    }
                    else
                    {
                        if (ora_mar_unmarshalUCS2(p_st_sess, p_st_ora_packet, &i_k) != FR_SUCC) // k
                            goto error;
                    }
                    j_loop += i_k;
                }
                m = 2;
                break;
            default:;
        }
    }

    return FR_SUCC;
error:
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  对应于 ojdbc7_12.1.0.1 oracle.jdbc.driver.T4C8TTILobd.java unmarshalLobData()
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_ttc8_tti_lobd_unmarshalLobData(Conntrack *p_st_conn
                                    , L7session_ora *p_st_sess
                                    , L7_ora_packet *p_st_ora_packet)
{
    ORA_PRINT_INFO("ora_ttc8_tti_lobd_unmarshalLobData...\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_ora_private *p_st_session_private = (L7session_ora_private *) frct_get_session_private(p_st_session);
    L7_ora_curr_session *p_st_curr_sess = p_st_session_private->p_st_curr_sess;
    uint64_t uint64_lob_data_len = 0;
    unsigned long long ull_skip = 0;
    int i_remaining = 0;

    if (bytebuff_remaining(p_st_ora_packet->p_st_packet) == 0)
    {
        ora_packet_need_next_packet(p_st_ora_packet);
        p_st_ora_packet->i_need_next_packet_lob = FR_YES;
        goto error;
    }
    p_st_ora_packet->i_need_next_packet_lob = FR_NO;

    /**
     * FIXME: 完整的逻辑见ojdbc7_12.1.0.1 oracle.jdbc.driver.T4C8TTILob.java readLOBD()
     *      boolean bool = this.connection.isZeroCopyIOEnabled() & (this.sourceLobLocator[7] & 0xFFFFFF80) != 0;
     *
     *      这里useZeroCopyIO的判断只支持了一部分。
     *      if ((this.serverRuntimeCapabilities != null) &&
     *          (this.serverRuntimeCapabilities.length > 6) &&
     *          ((this.serverRuntimeCapabilities[6] & T4C8TTIdty.KPCCAP_RTB_TTC_ZCPY) != 0) &&
     *          (this.thinNetUseZeroCopyIO) &&
     *          ((this.net.getSessionAttributes().getNegotiatedOptions() & 0x40) != 0) &&
     *          (getDataIntegrityAlgorithmName().equals("")) &&
     *          (getEncryptionAlgorithmName().equals(""))) {
     *          this.useZeroCopyIO = true;
     *      } else {
     *          this.useZeroCopyIO = false;
     *      }
     */

    ORA_PRINT_DBG("* ora_has_svr_compile_time_capability(p_st_sess, 6, 1)? [%d]\n", ora_has_svr_compile_time_capability(p_st_sess, 6, 1));
    ORA_PRINT_DBG("* accept negotiated options? [0x%04x]\n", p_st_sess->s_negotiated_options);
    ORA_PRINT_DBG("c_lob_source_locator_7[0x%02x][%s]\n", p_st_curr_sess->c_lob_source_locator_7, (p_st_curr_sess->c_lob_source_locator_7 & 0xFFFFFF80) != 0 ? "YES" : "NO");

    if (ora_has_svr_compile_time_capability(p_st_sess, 6, 1) == FR_SUCC &&
            (p_st_sess->s_negotiated_options & 0x40) != 0 &&
            (p_st_curr_sess->c_lob_source_locator_7 & 0xFFFFFF80) != 0)
    {
        if (ora_mar_skip(p_st_ora_packet, 12) != FR_SUCC)
            goto error;
        if (bytebuff_get_long(p_st_ora_packet->p_st_packet, 4, &uint64_lob_data_len, BYTE_BIG_ENDIAN) != FR_SUCC)
            goto error;
        ull_skip = uint64_lob_data_len + 56;
        ORA_PRINT_DBG("lob_data_len:[%lu]\n", uint64_lob_data_len);
        i_remaining = bytebuff_remaining(p_st_ora_packet->p_st_packet);
        if ((unsigned long long) i_remaining < ull_skip)
        {
            ora_packet_need_next_packet(p_st_ora_packet);
            p_st_ora_packet->ul_skip_len = (unsigned long) (ull_skip - i_remaining);
            bytebuff_set_skip(p_st_ora_packet->p_st_packet, (size_t) (ull_skip));
            goto error;
        }
        if (ora_mar_skip(p_st_ora_packet, ull_skip) != FR_SUCC)
            goto error;
    }
    else
    {
        ORA_PRINT_INFO("ora_ttc8_tti_lobd_unmarshalLobData not use zero copy...\n");
        if (ora_mar_skipCLR(p_st_sess, p_st_ora_packet) != FR_SUCC)
            goto error;
    }

    ORA_PRINT_INFO("leave ora_ttc8_tti_lobd_unmarshalLobData\n");
    return FR_SUCC;
error:
    return FR_FAIL;
}
